/** 数组模块 */
import {
	pickObj,
	assign,
	pairs,
	contains
} from './object'

/**
 * @name: object
 * @cname: 数组转对象
 * @desc: 将数组转成对象
 * @param {*}  arr
 * @panme: arr=[["a",1],["b":2]]
 * @result: {a:1,b:2}
*/
export let object = arr => arr.reduce((res, r) => assign(res, { [r[0]]: r[1] }), {})

/**
 * @name: compact
 * @cname: 返回元素
 * @desc: 返回原数组或对象中所有的非假值元素
 * @param {*}  source
 * @panme: source=[1,0,false]
 * @result: [1]
*/
export let compact = (source) => {
	if (Array.isArray(source)) return source.filter(r => r)
	return object(pairs(source).filter(([, v]) => v))
}

/**
 * @name: filterByPartItem
 * @cname: 筛选所有项
 * @desc: 根据数组项(对象)的部分属性，筛选出符合此条件的所有项
 * @param {*}  source dict 
 * @panme:  source=[{ a: 1, b: 2, c: 1 },{ a: 1, b: 2, c: 2 } ,{ a: 1, b: 3, c: 2 } ] dict={ a: 1, b: 2 }
 * @result: [{ a: 1, b: 2, c: 1 },{ a: 1, b: 2, c: 2 }]
*/
export let filterByPartItem = (source, dict) => source.filter(r => contains(r, compact(dict)))

/**
 * @name: compactByKey
 * @cname: 返回key值
 * @desc: 返回原对象数组中某key的非假值
 * @param {*}  source
 * @panme: source=[1,0,false]
 * @result: [1]
*/
export let compactByKey = (source, key) => source.filter(r => r[key])

/**
 * @name: arrayLike2Array
 * @cname: 类数组转换数组
 * @desc: 把传入的类数组转化成数组
 * @param {*} arr 传入参数
 * @panme: arr={0:'a',1:'b',2:'c',3:'d',length:4} 
 * @result: ['a', 'b', 'c', 'd']
*/
export default function arrayLike2Array(arr) {
	let {
		length
	} = arr
	let res = new Array(length)
	for (let i = 0; i < length; i++) {
		res[i] = arr[i];
	}
	return res;
}

/**
 * @name: isEmptyArr
 * @cname: 是否是空数组
 * @desc: 检查传入的数据是否是空数组
 * @param {*} arr  传入参数
 * @panme: arr=[1]
 * @result: flase
*/

export let isEmptyArr = (arr) => !arr || !arr.length


/**
 * @name: merge
 * @cname: 按条件合并数组
 * @desc: 传入两个数组再传入合并条件按条件合并数组
 * @param {*} a 传入参数 b传入参数 fn 传入条件函数
 * @panme: [{id:1,name:'ace'},{id:2,name:'zzz'}]和[{id:1,age:20}]
 * @result: [[{id:1,name:'ace',age:20},{id:2,name:'zzz'}]]
*/

export function merge(a, b, fn) {
	return a.map(r => {
		let bb = b.find(rr => fn(r, rr)) || {}
		return {
			...r,
			...bb
		}
	})
}


/**
 * @name: sum
 * @cname: 总和
 * @desc: 算出数组的某字段的和，如未读数量
 * @param {*} arr 传入数组 fn 传入方法函数
 * @panme: arr:[{ count: 111 }, { count: 444 }]  fn:r => r.count
 * @result: 555
*/

export let sum = (arr, fn) => arr.reduce((t, r) => t + fn(r), 0)

/**
 * @name: pick
 * @cname: 挑选字段
 * @desc: 从对象或者对象数组中择出你要的字段，如将form瘦身
 * @param {*} obj 传入对象 keys 传入字段
 * @panme: obj:{ a: 1, b: 2, c: 3, d: 4 } keys:['b','d']
 * @result:  [{  b: 2, d: 4 }]
*/

export function pick(obj, keys) {
	if (!obj) return;
	if (Array.isArray(obj)) return obj.map(r => pickObj(r, keys))
	return pickObj(obj, keys)
}

/**
 * @name: indexOf
 * @cname: 位置索引
 * @desc: 元素在数组中第一次出现位置
 * @param {*} arr obj 
 * @panme: arr=[1,2,3,4,5,6,7] obj=3
 * @result: 2
*/

export function indexOf(arr, obj) {
	for (let i = 0; i < arr.length; i++) {
		if (arr[i] === obj) return i
	}
	return -1
}

/**
 * @name: lastIndexOf
 * @cname: 最后位置索引
 * @desc: 元素在数组中最后出现位置
 * @param {*} arr obj 
 * @panme:  arr=[1,2,3,4,5,6,7] obj =3
 * @result: 4
*/
export function lastIndexOf(arr, obj) {
	for (let i = arr.length - 1; i >= 0; i--) {
		if (arr[i] === obj) return i
	}
	return -1
}

/**
 * @name: push
 * @cname: 末端添加
 * @desc: 向数组末尾添加元素
 * @param {*} arr  obj 
 * @panme:  arr=[1,2,3,4,5,6,7] obj=3
 * @result:[1, 2, 3, 4, 2, 6, 7, 2]
*/
export function push(arr, obj) {
	arr[arr.length] = obj
	return arr
}

/**
 * @name: join
 * @cname: 加入
 * @desc: 把数组转化成字符串并加入code
 * @param {*} arr code 
 * @panme: arr=[1,2,3,4,5,6,7] code=''
 * @result: 123426
*/
export function join(arr, code = "") {
	var str = ""
	for (let i = 0; i < arr.length; i++) {
		str += (arr[i] + code)
	}
	return str.substring(0, str.length - 1)
}
/**
 * @name: remove
 * @cname: 删除元素
 * @desc: 删除相应的元素
 * @param {*} arr obj
 * @panme: arr=[1,2,3,4,5,6,7] obj=2
 * @result: [1,3,4,5,6,7]
*/
export function remove(arr, obj) {
	var index = arr.indexOf(obj)
	if (index > -1) arr.removeAt(index)
	return arr
}

/**
 * @name: removeAt
 * @cname: 根据下标删除元素
 * @desc: 根据对应的下标删除相应的元素
 * @param {*} arr index 
 * @panme: arr=[1,2,3,4,5,6,7]  index=2
 * @result: [1, 2, 4, 2, 6, 7]
*/
export function removeAt(arr, index) {
	if (index >= 0 && index < arr.length) arr.splice(index, 1)
	return arr
}

/**
 * @name: removeAll
 * @cname: 删除所有对应元素
 * @desc: 查询数组删除数组内所有的对应元素
 * @param {*} arr obj
 * @panme: arr=[1,2,2,3,4,5,6] obj=2
 * @result: [1,3,4,5,6,]
*/
export function removeAll(arr, obj) {
	//找元素在数组中的位置
	var index = indexOf(arr, obj)
	//如果找到了
	if (index > -1) {
		//从数组中根据下标删掉
		removeAt(arr, index)
		//再次调用自身,直到数组中找不到此元素为止
		arguments.callee.call(arr, obj)
	}
}
/**
 * @name: splice
 * @cname: 截取
 * @desc: 根据下标截取处相应的部分
 * @param {*} arr index count
 * @panme: arr=[1,2,3,4,5,6,7] index=2 count=2
 * @result: [3,4]
*/
export function splice(arr, index, count) {
	for (let i = index; i < arr.length - 1; i++) {
		arr[i] = arr[i + count]
	}
	for (let i = 0; i < count; i++) pop(arr)
	return arr
}
/**
 * @name: shift
 * @cname: 删除元素
 * @desc: 创建一个数组，并删除数组的第一个元素
 * @param {*} arr 
 * @panme: arr=[1,2,3]
 * @result: [2,3]
*/
export function shift(arr) {
	var result = arr[0]
	splice(arr, 0, 1)
	return result
}
/**
 * @name: reverse
 * @cname: 数组翻转
 * @desc: 将数组整体反转颠倒
 * @param {*} arr 
 * @panme: arr = [1, 2, 3, 4, 2, 6, 7]
 * @result: [7,6,5,4,3,2,1]
*/
export function reverse(arr) {
	for (let i = 0; i < Math.floor(arr.length / 2); i++) {
		var temp = arr[i]
		arr[i] = arr[arr.length - 1 - i]
		arr[arr.length - 1 - i] = temp
	}
	return arr
}

/**
 * @name: insertAt
 * @cname: 插入
 * @desc: 在相应下标的位置插入数据
 * @param {*} arr index obj
 * @panme: arr=[1,2,3,4,2,6,7] index=2 obj=2
 * @result: [1,2,2,3,4,2,6,7]
*/
export function insertAt(arr, index, obj) {
	if (index < 0 || index > arr.length) throw new Error("参数有误")
	for (let i = arr.length - 1; i >= index; i--) {
		arr[i + 1] = arr[i]
	}
	arr[index] = obj
	return arr
}

/**
 * @name: unshift
 * @cname: 添加元素
 * @desc: 往开头添加元素
 * @param {*} arr obj
 * @panme: arr=[1,2,3,4,2,6,7] obj=7
 * @result: [7, 1, 2, 3, 4, 2, 6, 7]
*/
export function unshift(arr, obj) {
	return insertAt(arr, 0, obj)
}

/**
 * @name: pop
 * @cname: 返回元素
 * @desc: 返回最后一个元素
 * @param {*} arr 
 * @panme: arr=[1,2,3,4,2,6,7]
 * @result: 7
*/
export function pop(arr) {
	var result = arr[arr.length - 1]
	arr.length -= 1
	return result
}

/**
 * @name: forEach
 * @cname: 循环
 * @desc: 调用数组的每个元素并将元素传递给回调函数
 * @param {*} arr fn 
 * @panme: arr=[1,2,3,4,5,6]   fn = (a, b) => {return a + b}
 * @result: [1,3,5,7,9,11]
*/
export function forEach(arr, fn) {
	for (let i = 0; i < arr.length; i++) {
		fn(arr[i], i)
	}
	return arr
}
/**
 * @name: some
 * @cname: 元素判断
 * @desc: 用于检测数组中的元素是否满足指定条件满足则返回true并且后面的不再检查
 * @param {*} arr fn 
 * @panme: arr= [3, 10, 18, 20] fn=(a,b)={return a>= b;}
 * @result: true
*/
export function some(arr, fn) {
	for (let i = 0; i < arr.length; i++) {
		if (fn(arr[i], i)) return true
	}
	return false
}

/**
 * @name: every
 * @cname: 检测元素
 * @desc: 用于检测数组所有元素是否都符合指定条件有一个不满足则返回flase
 * @param {*} arr 
 * @panme: arr= [3, 10, 18, 20] fn=(a,b)={return a>= b;}
 * @result: true
*/
export function every(arr, fn) {
	for (let i = 0; i < arr.length; i++) {
		if (!fn(arr[i], i)) return false
	}
	return true
}

/**
 * @name: count
 * @cname: 计数
 * @desc: 统计满足条件的元素数量
 * @param {*} arr fn
 * @panme: arr= [3, 10, 18, 20] fn=(a,b)={return a>= b;}
 * @result: 4
*/
export function count(arr, fn) {
	var result = 0
	forEach(arr, function (r, i) {
		if (fn(r, i)) result++
	})
	return result
}

/**
 * @name: filter
 * @cname: 筛选
 * @desc: 创建一个新的数组 新数组中的元素是通过检查指定数组中符合条件的所有元素
 * @param {*} arr fn
 * @panme: arr=[1,2,0,4,5,6]   fn = (a, b) => {return a>b}
 * @result: [1,2,4,5,6] 
*/
export function filter(arr, fn) {
	var result = []
	forEach(arr, function (r, i) {
		if (fn(r, i)) result.push(arr)
	})
	return result
}

/**
 * @name: map
 * @cname: 遍历处理
 * @desc: 返回一个新数组 数组中的元素为原始数组元素调用函数处理后的值
 * @param {*} arr fn
 * @panme: arr=[1, 2, 3] fn=(a,b)=>{return item * 2}
 * @result: [2, 4, 6]
*/
export function map(arr, callback) {
	var result = []
	for (let i = 0; i < arr.length; i++) {
		result.push(callback(arr[i], i))
	}
	return result
}

/**
 * @name: includes
 * @cname: 查找
 * @desc: 判断数组是否包含某个元素相应返回true或flase
 * @param {*} arr obj
 * @panme: arr = [1, 2, 3, 4, 2, 6, 7] obj = 7
 * @result: true
*/
export function includes(arr, obj) {
	return indexOf(arr, obj) > -1
}

/**
 * @name: find
 * @cname: 查找数值
 * @desc: 方法返回通过测试（函数内判断）的数组的第一个元素的值。
 * @param {*} arr fn
 * @panme: arr = [1, 1, 3, 4, 2, 6, 7] fn=(a,i)=>{return a==i}
 * @result: 1
*/
export function find(arr, fn) {
	for (let i = 0; i < arr.length; i++) {
		if (fn(arr[i], i)) return arr[i]
	}
}

/**
 * @name: findIndex
 * @cname: 查找数值下标
 * @desc: 返回传入一个测试条件（函数）符合条件的数组第一个元素位置
 * @param {*} arr fn
 * @panme: arr = [1, 1, 3, 4, 2, 6, 7] fn=(arr,i)=>{return arr==i}
 * @result: 1
*/
export function findIndex(arr, fn) {
	for (let i = 0; i < arr.length; i++) {
		if (fn(arr[i], i)) return i
	}
}